<template>
  <div class="main">
    <div class="wrap">
      <!-- 头部 -->
      <div class="titleBox">
        <img
          src="http://101.43.223.224:8765/image/getImageById?id=6917"
          alt="" class="head_portrait" />
        <span style="color: #fff">官方客服</span>
        <!-- 在线状态弹框 -->
        <el-popover placement="bottom" trigger="click">
          <div class="stateBox2" @click="uploadState(1)">
            <span class="state2"></span>
            <span class="stateText">离线</span>
          </div>
          <div class="stateBox2" @click="uploadState(2)">
            <span class="state1"></span>
            <span class="stateText">在线</span>
          </div>

          <div class="stateBox" slot="reference" v-if="state == 1">
            <span class="state2"></span>
            <span class="stateText">离线</span>
          </div>
          <div class="stateBox" slot="reference" v-if="state == 2">
            <span class="state1"></span>
            <span class="stateText">在线</span>
          </div>
        </el-popover>
      </div>
      <!-- 底部 -->
      <div class="infoBox">
        <!-- 左边用户列表 -->
        <div class="userList">
          <div class="userListBox">
            <div v-for="(item, index) in userListData" :key="index" @click="getAct(item, index)"
              :class="item.id == act ? 'userFlexAct' : 'userFlex'">
              <div>
                <img :src="item.setAvatarUrl" alt="头像" class="head_portrait3" />
              </div>
              <div class="margin1">
                <el-tooltip :content="item.username" placement="bottom" effect="light">
                  <div class="margin2 userName"> {{ item.username }}</div>
                </el-tooltip>
                <div class="userInfo">{{ item.message }}</div>
              </div>
              <div class="margin3">{{  formatTime(item.time ) }}</div>
            </div>
          </div>
        </div>
        <!-- 右边输入框和信息展示 -->
        <div class="infoList">
          <!-- 信息 -->
          <div class="infoTop" ref="scrollBox" id="box">
            <div :class="item.position == 'left' ? 'chatInfoLeft' : 'chatInfoRight'"
            v-for="(item, index) in userInfoList" :key="index">
              <img :src="item.setAvatarUrl" alt="头像" class="head_portrait2" />
              <div :class="item.position == 'left' ? 'chatLeft' : 'chatRight'">

                <template v-if="item.type === 'text' || item.type === 'recall'" id="recall">
                    <div class="text" v-html="item.message"  @contextmenu="handleRightClick($event,item)"></div>
                </template>

                <template v-else-if="item.type === 'image'">
                    <img :src="item.message" alt="图片" class="chatImage"  @contextmenu="handleRightClick($event,item)" />
                </template>
                <template v-else-if="item.type === 'video'">
                    <video :src="item.message" controls class="chatVideo"  @contextmenu="handleRightClick($event,item)"></video>
                </template>
                <template  v-else-if="item.type === 'file'">
                   <a :href="item.message">
                     <img src="../../assets/images/文件.png"   @contextmenu="handleRightClick($event,item)" class="chatVideo" title="点击查看"/>
                   </a>
                </template>
              </div>
            </div>
          </div>
          <!-- 输入框 -->
          <div class="infoBottom">
            <div class="infoIcon">
              <input type="file" style="display: none;" id="fileInput">
              <i @click="chooseImage()" class="el-icon-picture-outline-round"></i>
              <i @click="chooseImage()" class="el-icon-folder-opened"></i>
              <i @click="chooseImage()" class="el-icon-video-camera"></i>
            </div>
           <textarea type="textarea" class="infoInput" v-model="textarea"
              @keydown.enter.exact="handlePushKeyword($event)" @keyup.ctrl.enter="lineFeed"
              :disabled="isshow == 1 ? false : true" />
            <div class="fasong" @click="sendMessage()" v-show="isshow == 1 ? true : false">
              发送
            </div>
          </div>
        </div>
      </div>
    </div>
    </el-dialog>
  </div>
</template>


<script>
  import { getUserId } from "@/api/system/user";
  export default {
    data() {
      return {
        senderId:'',  //当前登录人
        username:'',// 固定名称
        receiverId: '',//表示发送给哪个用户
        receiverName:'',//表示发送给哪个用户
        setAvatarUrl:'http://101.43.223.224:8765/image/getImageById?id=6917',
        path: "ws://localhost:7888/ws/", //后台的websocket地址，找后端要
        ws: null, //建立的连接
        timeout: 10 * 1000, //30秒一次心跳
        timeoutObj: null, //心跳心跳倒计时
        serverTimeoutObj: null, //心跳倒计时
        userListData: [],
        state: 1,// 状态
        search: "",//搜索用户
        act: Number,//用户点击选中变色
        dialogVisible: false, // 加号弹框
        userInfoList: [],//历史信息
        textarea: "",//输入框
        scrollTop: 0,//滚动条距离顶部距离
        isshow: 1,//发送和输入显隐
      };
    },
    beforeDestroy() {
      if (this.ws) {
          this.ws.close(); // 关闭WebSocket连接
	  }
      clearTimeout(this.timeoutObj);// 清除时间
      clearTimeout(this.serverTimeoutObj);
    },
    created() {
        this.getUserId();
    },
    methods: {
       handleRightClick(event,item) {
         if(item.username !==this.username){
         	 return;
         }
         if(item.message === '消息已撤回' && item.type === 'recall' ){
         	return;
         }
         item.type='recall';
          event.preventDefault(); // 阻止默认右键菜单
          if (item.username === this.username) {
              if (confirm('是否撤回信息？')) {
                this.ws.send(JSON.stringify(item));
                item.message="消息已撤回";
              } else {
                alert("撤回失败")
              }
          }
        },

      getUserId() {
        this.username=sessionStorage.getItem('username'); //获取当前登录的用户名称

        getUserId(this.username).then(response => {
          this.senderId=response.data.id;
        });
      },


      formatTime(timestamp) { //发送信息的时间
      	const date = new Date(timestamp);
      	const hours = date.getHours();
      	const minutes = date.getMinutes();

      	return `${hours}:${minutes < 10 ? '0' + minutes : minutes}`;

      },

      uploadState(state) { //切换客服状态
        if (state === 1) {
          this.state = state;
          this.offline();
        }
         this.state = state;
         this.initWebpack();
      },

      handlePushKeyword(event) { // 监听键盘回车阻止换行并发送
        if (event.keyCode === 13) {
          event.preventDefault(); // 阻止浏览器默认换行操作
          return false;
        }
      },

      lineFeed() { // 监听按的是ctrl + 回车，就换行
        this.textarea = this.textarea + "\n";
      },


      setPageScrollTo(s, c) {//滚动条默认滚动到最底部
        this.scrollTop = document.querySelector("#box").offsetHeight;//获取中间内容盒子的可见区域高度
        setTimeout((res) => {//加个定时器，防止上面高度没获取到，再获取一遍。
          if (this.scrollTop != this.$refs.scrollBox.offsetHeight) {
            this.scrollTop = document.querySelector("#box").offsetHeight;  //scrollTop：滚动条距离顶部的距离。
          }
        }, 100);
        this.$refs.scrollBox.scrollTop = this.scrollTop;//把上面获取到的高度座位距离，把滚动条顶到最底部
        if (this.$refs.scrollBox.scrollTop > 0) { //判断是否有滚动条,有滚动条就创建一个监听滚动事件，滚动到顶部触发srTop方法
          this.$refs.scrollBox.addEventListener("scroll", this.srTop);
        }
      },


      //-----------------------以下是websocket部分方法

      initWebpack() { // 初始化websocket链接
         if (this.state===2) {
            if (typeof WebSocket === "undefined") {
              alert("您的浏览器不支持socket");
            } else {
              this.ws = new WebSocket(this.path + this.username); //  链接后端websocket 实例
              this.ws.onmessage = this.onmessage; //监听后台返回消息
            }
          } else {
            this.offline();
            console.log("用户离线，不连接 WebSocket");
          }
      },

      offline() { // 用户离线时断开连接
        if (this.ws) {
          this.ws.close();
        }
      },

      sendMessage() { //发送信息
        if(this.textarea === ''){
          return;
        }

          const message = {// 构造要发送的消息对象
              type: 'text',
              message: this.textarea,
              receiverId:this.receiverId,
              receiverName:this.receiverName,
              time:Date.now(),
              senderId:this.senderId,
              username:this.username,
              setAvatarUrl:this.setAvatarUrl,
          };
          this.userInfoList.push(message);
          // 将消息对象转换为 JSON 字符串
          const messageString = JSON.stringify(message);
          this.$nextTick(() => { // 一定要用nextTick
            this.setPageScrollTo();
            this.textarea = ''; // 清空输入框
            this.ws.send(messageString);
            this.$refs.scrollBox.scrollTop = this.$refs.scrollBox.scrollHeight;
          })
      },

      onmessage(event) {//接收信息
        const message = JSON.parse(event.data); // 假设服务器发送的消息是JSON格式
        const position = message.username === this.username ? 'right' : 'left'; //判断信息是左边还是右边

        this.userInfoList = this.userInfoList.filter((userInfo) => {
            return !(message.type === 'recall' && userInfo.message === message.message);
        });
        this.userListData = this.userListData.filter((userInfo) => {
            return !(message.type === 'recall' && userInfo.message === message.message);
        });
        if(message.type === 'recall'){
          message.message="对方信息已撤回";
        }

        this.userInfoList.push({
          setAvatarUrl: message.setAvatarUrl, // 头像
          position: position, // 根据消息来源设置消息显示位置
          message: message.message ,// 消息内容
          time: message.time ,// 时间
          senderId: message.senderId ,// 当前登录人id
          username:message.username  ,// 当前登录人名称
          receiverName:message.receiverName, //发送人名称
          receiverId:message.receiverId, //发送人id
          type:message.type ,   //信息类型
        });
        this.userListData.push(message);
        this.receiverId=message.senderId;
        if(this.username!==message.username ){  //防止，我发信息时候，将对面的id顶掉
          this.receiverName=message.username; //发送信息的人
        }

        // 页面滚动到底部
        this.$nextTick(() => {
          this.$refs.scrollBox.scrollTop = this.$refs.scrollBox.scrollHeight;
        });
      },

      chooseImage() {
          const fileInput = document.getElementById('fileInput');
          // 移除旧的监听器以防止重复绑定
          fileInput.onchange = null;
          fileInput.onchange = (e) => {
              const file = e.target.files[0];
              let MAX_IMAGE_SIZE = 5 * 1024 * 1024; // 5MB for image
              let MAX_VIDEO_SIZE = 10 * 1024 * 1024; // 20MB for video
              let MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB for file
              let fileType;
              let maxSize;
              const fileName = file.name.split('.').pop();
              if (fileName === 'jpg' || fileName === 'jpeg' || fileName === 'png') {
                  fileType = 'image';
                  maxSize = MAX_IMAGE_SIZE;
              } else if (fileName === 'mp4' || fileName === 'mov') {
                  fileType = 'video';
                  maxSize = MAX_VIDEO_SIZE;
              } else if (fileName === 'docx' || fileName === 'pdf') {
                  fileType = 'file';
                  maxSize = MAX_FILE_SIZE;
              } else {
                  alert('不支持的文件类型');
                  return;
              }
              if (file.size > maxSize) {
                  alert(`文件太大，请选择小于${maxSize / (1024 * 1024)}MB的文件`);
                  return;
              }
              const reader = new FileReader();
              let receiverId2=this.receiverId;
              reader.onload = (event) => {
                  const base64Data = event.target.result.split(',')[1]; // 去除前缀部分，将文件转换为Base64编码的字符串
                  const messageData = {
                      message: base64Data,
                      senderId: this.senderId,
                      username:this.username,
                      receiverId:receiverId2,
                      receiverName:this.receiverName,
                      time: Date.now(),
                      type: fileType,
                      file: fileName,
                      setAvatarUrl:this.setAvatarUrl
                  };
                  this.ws.send(JSON.stringify(messageData));// 在这里通过WebSocket发送消息数据到服务器
              };
              if (file) {
                  reader.readAsDataURL(file);
              }
          };
          fileInput.click();
      }


    },
  };
</script>

<style scoped>
  .chatVideo{
      width: 150px;
      height: 100px;
  }

  /* 对方发的信息样式 */
  .chatInfoLeft {
    min-height: auto;
    margin-left: 10px;
    margin-top: 10px;
    display: flex;
    align-items: flex-start; /* 从顶部开始显示内容 */
  }

  /* 自己发的信息样式 */
  .chatInfoRight {
    height: auto;
    margin-left: 10px;
    margin-top: 10px;
    display: flex;
    flex-direction: row-reverse;
    align-items: flex-start; /* 从顶部开始显示内容 */
  }

/*  图片的大小*/
  .chatImage{
    width: 150px;
    height: 100px;
  }
  .margin3 {
    margin-right: 10px;
    font-size: 14px;
    color: #ccc;
  }

  .margin2 {
    color: #565656;

  }

  .margin1 {
    margin-right: 40px;
  }

  .main {
    height: 100%;
    width: 100%;
  }

  .wrap {
    height: 80%;
    width: 55%;
    background-color: #f2f2f2;
    margin: auto;
    transform: translateY(10%);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
    border-radius: 10px;
  }

  .titleBox {
    height: 70px;
    width: 100%;
    background-image: linear-gradient(to right, #1e76bc, #69a3d5);
    display: flex;
    align-items: center;
    border-top-right-radius: 10px;
    border-top-left-radius: 10px;
  }

  .infoBottom {
    height: 30%;
    display: flex;
    flex-direction: column;
  }

  /* 输入框 */
  .infoInput {
    height: 58%;
    width: 100%;
    border: none;
    resize: none;
    padding: 10px;
    box-sizing: border-box;
    background-color: #f2f2f2;
    color: #434343;
  }

  .fasong {
    height: 30px;
    width: 80px;
    background-color: #e8e8e8;
    text-align: center;
    line-height: 30px;
    border-radius: 4px;
    color: #58df4d;
    margin-top: 1%;
    align-self: flex-end;
    margin-right: 20px;
    cursor: pointer;
  }

  .infoIcon {
    height: 40px;
    width: 100%;
    display: flex;
    align-items: center;
  }

  .infoIcon i {
    font-size: 24px;
    color: #676767;
    margin-left: 15px;
    cursor: pointer;
  }

  /* 头像 */
  .head_portrait {
    margin-left: 20px;
    margin-right: 20px;
    width: 3rem;
    height: 3rem;
    border-radius: 50%;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
  }

  .head_portrait3 {
    margin-left: 20px;
    width: 3rem;
    height: 3rem;
    border-radius: 50%;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
  }

  .head_portrait2 {
    width: 3rem;
    height: 3rem;
    border-radius: 50%;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
  }

  .stateBox {
    margin-left: 20px;
    padding: 1px 8px;
    background-color: #fff;
    border-radius: 10px;
    text-align: center;
    cursor: pointer;
  }

  .stateBox2 {
    margin-left: 20px;
    padding: 1px 8px;
    background-color: #fff;
    border-radius: 10px;
    text-align: center;
    cursor: pointer;
  }

  .stateBox2:hover {
    background-color: #dcdcdc;
  }

  /* 在线 */
  .state1 {
    display: inline-block;
    height: 10px;
    width: 10px;
    border-radius: 50%;
    background-color: #8ee80e;
  }

  /* 离线 */
  .state2 {
    display: inline-block;
    height: 10px;
    width: 10px;
    border-radius: 50%;
    background-color: #cacaca;
  }

  .stateText {
    font-size: 14px;
    margin-left: 5px;
  }

  /* 列表和信息 */
  .infoBox {
    height: 450px;
    width: 100%;
    display: flex;
  }

  /* 用户列表大盒子 */
  .userList {
    height: 100%;
    width: 300px;
    border-right: 1px solid #ccc;
    display: flex;
    flex-direction: column;
  }

  /* 用户列表 */
  .userListBox {
    flex: 1;
    width: 100%;
    overflow: auto;
  }

  /* 信息外层盒子 */
  .infoList {
    height: 100%;
    width: 72%;
  }

  /* 信息列表 */
  .infoTop {
    height: 70%;
    width: 100%;
    border-bottom: 1px solid #ccc;
    padding: 10px;
    box-sizing: border-box;
    overflow: auto;
  }



  .chatLeft {
    margin-left: 15px;
    flex: 1;
  }

  .chatLeft .text {
    color: #434343;
    margin-top: 8px;
    background-color: #e3e3e3;
    display: inline-block;
    padding: 6px 10px;
    border-radius: 10px;
    max-width: 50%;
    /* 忽略多余的空白，只保留一个空白 */
    white-space: normal;
    /* 换行显示全部字符 */
    word-break: break-all;
    white-space: pre-wrap;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
  }



  .chatRight {
    margin-right: 15px;
    flex: 1;
    /* 用align-items把元素靠右对齐 */
    display: flex;
    flex-direction: column;
    align-items: flex-end;
  }

  .chatRight .text {
    color: #434343;
    margin-top: 8px;
    background-color: #95ec69;
    display: inline-block;
    padding: 6px 10px;
    border-radius: 10px;
    max-width: 50%;
    /* 忽略多余的空白，只保留一个空白 */
    white-space: normal;
    /* 换行显示全部字符 */
    word-break: break-all;
    white-space: pre-wrap;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
  }

  .searchBox {
    padding: 4px 2px;
    border-bottom: 1px solid #ededed;
  }

  .input-with-select {
    width: 80%;
    margin-right: 2%;
  }

  /* 点击用户变色 */
  .userFlexAct {
    display: flex;
    justify-content: space-between;
    align-items: center;
    height: 70px;
    border-bottom: 1px solid #e8e8e8;
    cursor: pointer;
    background-color: #e8e8e8;
  }

  /* 用户默认颜色 */
  .userFlex {
    display: flex;
    justify-content: space-between;
    align-items: center;
    height: 70px;
    border-bottom: 1px solid #e8e8e8;
    cursor: pointer;
  }

  /* 用户名 */
  .userName {
    width: 100px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* 简略信息 */
  .userInfo {
    width: 100px;
    font-size: 14px;
    color: #ccc;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    margin-top: 3px;
  }

  /* 滚动条样式 */
  ::-webkit-scrollbar {
    width: 5px;
    height: 10px;
  }

  ::-webkit-scrollbar-thumb {
    background-color: #dbd9d9;
    border-radius: 3px;
  }
</style>
